﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Framework;
using ESRI.ArcGIS.ADF.CATIDs;
using BesAsm.Emgaats.Core;
using BesAsm.Emgaats.ModelResults;
using BesAsm.Framework.ModelResults;
using BesAsm.Framework.XpSwmmUtilities;
using BesAsm.Framework.EpaSwmm5Utilities;
using BesAsm.Framework.ArcGisUtilities;
using BesAsm.Framework.Reporting;
using BesAsm.MasterData.Entities;
using BesAsm.MasterData.Services;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.DataSourcesGDB;

namespace BesAsm.Emgaats.ModelResultsUI
{
  /// <summary>
  /// User interface for processing model results
  /// </summary>    
  [ClassInterface(ClassInterfaceType.None)]  
  public partial class ModelResultsUserControl : UserControl
  {    
    private ModelResultsExtension _modelResultsExtension;
    private IModelResultsHost _modelResultsHost;
    private ModelResultsSet _results;
    private TList<LayerFile> _layerFiles;

    public ModelResultsUserControl(object hook)      
    {
      InitializeComponent();

      Hook = hook;
      
      _modelResultsExtension = ModelResultsExtension.GetExtension();
      //_modelResultsExtension.RebindRequired += new EventHandler(OnRebindRequired);

      try
      {
        ConfigureModelResultsProviders();
      }
      catch (Exception ex)
      {
        Messenger.ReportMessage("Unable to configure Model Results Providers: " + ex.Message,
          BesAsm.Framework.Reporting.ReportableMessageType.Warning);
      }
    }

    /// <summary>
    /// Host object of the dockable window
    /// </summary>
    private object Hook
    {
      get;
      set;
    }

    /// <summary>
    /// Implementation class of the dockable window add-in. It is responsible for 
    /// creating and disposing the user interface class of the dockable window.
    /// </summary>
    public class AddinImpl : ESRI.ArcGIS.Desktop.AddIns.DockableWindow
    {
      private ModelResultsUserControl m_windowUI;

      public AddinImpl()
      {
      }

      protected override IntPtr OnCreateChild()
      {
        m_windowUI = new ModelResultsUserControl(this.Hook);
        return m_windowUI.Handle;
      }

      protected override void Dispose(bool disposing)
      {
        if (m_windowUI != null)
          m_windowUI.Dispose(disposing);

        base.Dispose(disposing);
      }

    } 

    private void ConfigureModelResultsProviders()
    {
      //TODO: This could be a plug-in architecture instead of explicitly registering providers
      _modelResultsHost = new EmgaatsModelResultsHost();
      _modelResultsHost.Register(new XpSwmmResultsProvider());
      _modelResultsHost.Register(new EmgaatsResultsProvider());
      _modelResultsHost.Register(new Swmm5ResultsProvider());
      //Register any additional ResultsProviders here

      cmbModelEngine.DataSource = _modelResultsHost.ResultsProviders;
      cmbModelEngine.DisplayMember = "ApplicationName";

    }

    private void btnBrowseResultFile_Click(object sender, EventArgs e)
    {
      IModelResultsProvider provider = null;
      try
      {
        if (cmbModelEngine.SelectedItem != null)
          provider = (IModelResultsProvider)cmbModelEngine.SelectedItem;

        openFileDialog1.Filter = provider.FileExtensionFilter;
        openFileDialog1.Title = provider.ApplicationName + " results file:";
        openFileDialog1.InitialDirectory =
          _modelResultsExtension.Model.GetPathIfSet(ModelPathComponent.RootFolder);

        if (openFileDialog1.ShowDialog() != DialogResult.OK)
        {
          _results = null;
          return;
        }

        string fileName = openFileDialog1.FileName;

        if (!File.Exists(fileName))
        {
          Messenger.ReportMessage("Unable to add results: Results file " +
            txtResultFile.Text + " not found",
            BesAsm.Framework.Reporting.ReportableMessageType.Warning);
          _results = null;
          return;
        }
        _results = provider.LoadResults(fileName);

        txtResultFile.Text = fileName;
        txtSimulationDate.Text = _results.SimulationDateTime.ToString("M/d/yyyy h:mm tt");
        txtSimulationDescription.Text = _results.Description;
        txtSimulationName.Text = _results.Name;
      }
      catch (Exception ex)
      {
        _results = null;
        return;
      }

    }

    private void btnNavigateBuildResultsLayers_Click(object sender, EventArgs e)
    {
      ultraTabControl1.SelectedTab = ultraTabControl1.Tabs["tabBuildResultsLayers"];
      
      LayerFileService lfs = new LayerFileService();

      _layerFiles = lfs.Find("category='" + LayerFile.Categories.ModelResults + "'");
      layerFileBindingSource.DataSource = _layerFiles;

    }

    private void btnCancelBuildResultsLayers_Click(object sender, EventArgs e)
    {
      ultraTabControl1.SelectedTab = ultraTabControl1.Tabs["tabSelectResultsFile"];
    }

    private void btnBuildResultsLayers_Click(object sender, EventArgs e)
    {
      try
      {
        if (_modelResultsExtension.Model == null ||
          _modelResultsExtension.Model.State == ModelState.Null)
        {
          MessageBox.Show("Unable to build model results layers: No model is loaded",
            "Unable to build model results layers", MessageBoxButtons.OK, MessageBoxIcon.Error);
          return;
        }
                
        EmgaatsResultsProvider emgaatsProvider = new EmgaatsResultsProvider();
        string filter = emgaatsProvider.FileExtensionFilter;

        string resultsFile = PromptResultFile(filter);
        if (resultsFile == null)
          return;
                
        SaveResults(emgaatsProvider, resultsFile);
        WriteLayerFiles(resultsFile);

      }
      catch (Exception ex)
      {
        string message = "Unable to build results layers";
        MessageBox.Show(message + ": " +
          ex.Message, message, MessageBoxButtons.OK, MessageBoxIcon.Error);
        Messenger.ReportMessage(message + ": " + ex.Message,
          BesAsm.Framework.Reporting.ReportableMessageType.Error);        
      }
    }

    private string PromptResultFile(string filter)
    {
      string resultsFile = Path.Combine(Path.GetDirectoryName(txtResultFile.Text),
          Path.GetFileNameWithoutExtension(txtResultFile.Text) + "_results.mdb");

      string pgdbPath = _modelResultsExtension.Model.GetPathIfSet(ModelPathComponent.Pgdb);

      saveFileDialog1.Filter = filter;
      saveFileDialog1.Title = "Create model results geodatabase:";
      saveFileDialog1.DefaultExt = "mdb";
      saveFileDialog1.FileName = resultsFile;

      if (saveFileDialog1.ShowDialog() != DialogResult.OK)
        return null;

      resultsFile = saveFileDialog1.FileName;

      if (resultsFile == pgdbPath)
      {
        MessageBox.Show(
          "The selected results database is the active model database; " +
          "Please select a different database",
          "Unable to overwrite model database",
          MessageBoxButtons.OK, MessageBoxIcon.Warning);
        return null;
      }
      else if (File.Exists(resultsFile))
      {
        File.Delete(resultsFile);
      }
      return resultsFile;
    }

    private void SaveResults(EmgaatsResultsProvider emgaatsProvider, string resultsFile)
    {
      string modelFile = _modelResultsExtension.Model.GetPathIfSet(ModelPathComponent.Pgdb);
      emgaatsProvider.SaveResults(_results, resultsFile, modelFile);
    }

    private void WriteLayerFiles(string resultsFile)
    {
      string path = Path.GetDirectoryName(resultsFile);
      string resultsFileName = Path.GetFileNameWithoutExtension(resultsFile);
      ArcGisUtils arcUtils = new ArcGisUtils(ArcMap.Application);
      
      IWorkspaceFactory workspaceFactory = new AccessWorkspaceFactoryClass();
      IFeatureWorkspace modelFws = (IFeatureWorkspace)workspaceFactory.OpenFromFile(resultsFile, 0);
      IFeatureClass fc = null;
      
      foreach (LayerFile lf in (TList<LayerFile>)layerFileBindingSource.DataSource)
      {
        lf.WriteLayer(path);
        fc = (IFeatureClass)modelFws.OpenFeatureClass(lf.AppliesToSchema);

        ESRI.ArcGIS.Carto.IFeatureLayer fl = new ESRI.ArcGIS.Carto.FeatureLayerClass();
        fl.Name = fc.AliasName;
        fl.FeatureClass = fc;
              
        ESRI.ArcGIS.Carto.IGeoFeatureLayer gfl = (ESRI.ArcGIS.Carto.IGeoFeatureLayer)fl;

        gfl.ApplyLayerFile(Path.Combine(path, lf.Name + ".lyr"));
                        
        arcUtils.MoveLayerToGroup((ESRI.ArcGIS.Carto.IFeatureLayer)gfl, resultsFileName);
      }

      return;
    }

    private void txtResultFile_TextChanged(object sender, EventArgs e)
    {
      if (!File.Exists(txtResultFile.Text))
        btnNavigateBuildResultsLayers.Enabled = false;
      else
        btnNavigateBuildResultsLayers.Enabled = true;
    }

  }
}
